//
//  6522Storage.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 04/09/2017.
//  Copyright 2017 Thomas Harte. All rights reserved.
//

#pragma once

#include <cstdint>

namespace MOS::MOS6522 {

class MOS6522Storage {
protected:
	// Phase toggle
	bool is_phase2_ = false;

	// The registers
	struct Registers {
		// "A low reset (RES) input clears all R6522 internal registers to logic 0"
		uint8_t output[2] = {0, 0};
		uint8_t input[2] = {0, 0};
		uint8_t data_direction[2] = {0, 0};
		uint16_t timer[2] = {0, 0};
		uint16_t timer_latch[2] = {0, 0};
		uint16_t last_timer[2] = {0, 0};
		int next_timer[2] = {-1, -1};
		uint8_t shift = 0;
		uint8_t auxiliary_control = 0;
		uint8_t peripheral_control = 0;
		uint8_t interrupt_flags = 0;
		uint8_t interrupt_enable = 0;

		bool timer_needs_reload = false;
		uint8_t timer_port_b_output = 0xff;
	} registers_;

	// Control state.
	struct {
		bool lines[2] = {false, false};
	} control_inputs_[2];

	enum class LineState {
		On, Off, Input
	};
	struct {
		LineState lines[2] = {LineState::Input, LineState::Input};
	} control_outputs_[2];

	enum class HandshakeMode {
		None,
		Handshake,
		Pulse
	} handshake_modes_[2] = { HandshakeMode::None, HandshakeMode::None };

	bool timer_is_running_[2] = {false, false};
	bool last_posted_interrupt_status_ = false;
	int shift_bits_remaining_ = 8;

	enum InterruptFlag: uint8_t {
		CA2ActiveEdge	= 1 << 0,
		CA1ActiveEdge	= 1 << 1,
		ShiftRegister	= 1 << 2,
		CB2ActiveEdge	= 1 << 3,
		CB1ActiveEdge	= 1 << 4,
		Timer2			= 1 << 5,
		Timer1			= 1 << 6,
	};

	enum class ShiftMode {
		Disabled = 0,
		InUnderT2 = 1,
		InUnderPhase2 = 2,
		InUnderCB1 = 3,
		OutUnderT2FreeRunning = 4,
		OutUnderT2 = 5,
		OutUnderPhase2 = 6,
		OutUnderCB1 = 7
	};
	bool timer1_is_controlling_pb7() const {
		return registers_.auxiliary_control & 0x80;
	}
	bool timer1_is_continuous() const {
		return registers_.auxiliary_control & 0x40;
	}
	bool is_shifting_out() const {
		return registers_.auxiliary_control & 0x10;
	}
	int timer2_clock_decrement() const {
		return 1 ^ ((registers_.auxiliary_control >> 5)&1);
	}
	int timer2_pb6_decrement() const {
		return (registers_.auxiliary_control >> 5)&1;
	}
	ShiftMode shift_mode() const {
		return ShiftMode((registers_.auxiliary_control >> 2) & 7);
	}
	bool portb_is_latched() const {
		return registers_.auxiliary_control & 0x02;
	}
	bool port1_is_latched() const {
		return registers_.auxiliary_control & 0x01;
	}
};

}
